#
# "@(#) $Id: PListParser.py,v 1.1.1.1 2006-07-27 03:16:08 gioshe Exp $"
#
# This work is released under the GNU GPL, version 2 or later.
#
from qt import *
from qt import QString
from qtxml import *
from time import gmtime,strftime,strptime
import os,re
from utils import *
#from codecs import *
	
#
# These classes handle the reading and writing of property lists (plists)
# to/from XML
#
class PListReader:
	def parse(self,filename):
		print "PListParser:: fname to parse::",filename
		if not os.access(filename,os.R_OK):
			return []
		else:
			buffer = open(filename).read()
			return self.parseString(buffer)
	
	def parseString(self,string):
		dom = QDomDocument('plist')
		if not dom.setContent(string):
			# XXX DSM throw error!
			print 'failed parse'
			return []
		return self.element(dom.documentElement())

	#
	# handle items of the form <tag>text</tag>, return the text
	#
	def text(self,element):
		value = element.toElement().firstChild().nodeValue()
		if type(value).__name__=='unicode':
			return value
		if type(value).__name__=='str':
			return unicode(value,'utf-8')
		return unicode(value)
		#return unicode(str(value),'utf-8')
	
	#
	# handle an arbitrary element
	#
	def element(self,element):
		element = element.toElement()
		if element.isNull():
			return None
		tag = str(element.tagName())
		if tag=='plist' or tag=='array':
			array = []
			child = element.firstChild()
			while not child.isNull():
				array.append(self.element(child))
				child = child.nextSibling()
			return array
		elif tag=='dict':
			dict = {}
			key = element.firstChild()
			while not key.isNull():
				value = key.nextSibling()
				dict[str(self.text(key))] = self.element(value)
				key = value.nextSibling()
			return dict
		elif tag=='integer':
			return int(self.text(element))
		elif tag=='real':
			return float(self.text(element))
		elif tag=='date':
			return strptime(self.text(element),"%Y-%m-%dT%H:%M:%SZ")
		elif tag=='string' or tag=='data':
			return self.text(element)
		elif tag=='true':
			return True
		elif tag=='false':
			return False
		
class PListWriter:
	def unparse(self,plist,filename):
		try:
			print "PListParser:: fname to write ",filename
			file = open(filename,"wb")
			lock(file)
			file.write(self.unparseToString(plist))
			unlock(file)
			file.close()
		except: 
			print "Could not write the settings file"
	
	def unparseToString(self,plist):
		return (u"<?xml version='1.0' encoding='UTF-8'?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"+unicode(self.unparseToDoc(plist).toString())).encode('utf-8')

	def unparseToDoc(self,plist):
		self.controlPattern = re.compile('[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x1f]')
		doc = QDomDocument('')
		root = doc.createElement('plist')
		root.setAttribute('version','1.0')
		doc.appendChild(root)
		self.unparseObject(doc,root,plist[0])
		return doc
	
	#
	# eliminate any control characters coming in
	#
	def cleanup(self,s):
		return '_'.join(self.controlPattern.split(s))

	#
	# create atomic elements of the form <tag>text</tag>
	#
	def atom(self,doc,parent,tag,text):
		obj = doc.createElement(tag)
		parent.appendChild(obj)
		obj.appendChild(doc.createTextNode(text))
		
	def unparseObject(self,doc,parent,obj):
		objClass = type(obj).__name__
		if objClass=='list':
			element = doc.createElement('array')
			parent.appendChild(element)
			for item in obj:
				self.unparseObject(doc,element,item)
		elif objClass=='dict':
			element = doc.createElement('dict')
			parent.appendChild(element)
			for key in obj.keys():
				self.atom(doc,element,'key',key)
				self.unparseObject(doc,element,obj[key])
		elif objClass=='int' or objClass=='long':
			self.atom(doc,parent,'integer',str(obj))
		elif objClass=='float':
			self.atom(doc,parent,'real',str(obj))
		elif objClass=='bool':
			if obj:
				parent.appendChild(doc.createElement('true'))
			else:
				parent.appendChild(doc.createElement('false'))
		elif objClass=='struct_time':
			self.atom(doc,parent,'date',strftime("%Y-%m-%dT%H:%M:%SZ",obj))
		elif objClass=='str':
			self.atom(doc,parent,'string',self.cleanup(unicode(obj,'latin-1')))
		elif objClass=='unicode':
			self.atom(doc,parent,'string',self.cleanup(obj))
		else:
			parent.appendChild(doc.createElement(objClass))

if __name__ == '__main__':
	ddfilename = "../.8traK/MusicLibrary.xml"
	reader = PListReader()
	plist = reader.parse(filename)
	print plist
	writer = PListWriter()
	writer.unparse(plist,filename)
